﻿using Swifter.Tools;
using System.Text.RegularExpressions;
using System;

namespace Swifter.Data.Sql.MsSql
{
    sealed class SqlBuilder_SqlServer : SqlBuilder
    {
        /// <summary>
        /// 单次查询最大数据行数。
        /// </summary>
        public static int MaxLimit { get; set; } = 999999999;


        const string Code_Global_Parameter_Identity = "@@IDENTITY";
        const string Code_Global_Parameter_RowCount = "@@ROWCOUNT";

        static readonly Regex StandardName = new Regex("^(@*[A-Za-z0-9_.]+)|\\*$");
        static readonly Regex ErrorName = new Regex("[\\[\\]']");

        public override string ProviderName => "System.Data.SqlClient";

        bool IsStandardName(string name) => /*StandardName.IsMatch(name)*/false;

        bool IsErrorName(string name) => ErrorName.IsMatch(name);

        string InjectCheck(string value) => value?.Replace("'", "''");
        
        public override void BuildName(string name)
        {
            if (IsStandardName(name))
            {
                BuildCode(name);
            }
            else if (IsErrorName(name))
            {
                throw new ArgumentException($"Object name format error -- [{name}].", nameof(name));
            }
            else
            {
                BuildCode(Code_Square_Brackets_Begin);

                BuildCode(name);

                BuildCode(Code_Square_Brackets_End);
            }
        }

        public override void BuildSelectLimit(int? offset, int? limit)
        {
            BuildCode(Code_Space);

            BuildCode(Code_Offset);

            BuildCode(Code_Space);

            BuildCode(NumberHelper.Decimal.ToString(Math.Max(offset ?? 0, 0)));

            BuildCode(Code_Space);

            BuildCode(Code_Rows);

            BuildCode(Code_Space);

            BuildCode(Code_Fetch);

            BuildCode(Code_Space);

            BuildCode(Code_Next);

            BuildCode(Code_Space);

            BuildCode(NumberHelper.Decimal.ToString(Math.Min(limit ?? MaxLimit, MaxLimit)));

            BuildCode(Code_Space);

            BuildCode(Code_Rows);

            BuildCode(Code_Space);

            BuildCode(Code_Only);
        }

        public override void BuildValue(SqlValue<string> value) => BuildCode($"N'{InjectCheck(value.Value)}'");

        public override OrderBy GetDefaultOrderBy(SelectStatement selectStatement)
        {
            return new OrderBy(new Column(null, Code_One), OrderByDirections.None);
        }

        public override void BuildStatementEnd()
        {
            BuildCode(Code_Semicolon);

            BuildCode(Code_WrapLine);
        }

        public override SqlBuilder CreateInstance() => new SqlBuilder_SqlServer();

        public override void BuildTable(SelectStatement selectStatement)
        {
            if (selectStatement.OrderBys.Count != 0 && selectStatement.Limit == null)
            {
                selectStatement.Limit = MaxLimit;
            }

            base.BuildTable(selectStatement);
        }
    }
}